#ifndef     __REDIS_H_INCLUDED__
#define     __REDIS_H_INCLUDED__

#include	<functional>
#include	<map>
#include	<string>
#include	<vector>

struct redisContext;
struct redisAsyncContext;
struct redisReply;

/**
 * Tools to using Redis in server.
 */
namespace Redis {

	/**
	 * C++ version of redisReply
	 */
	class Reply {
	public:
		Reply(redisReply * reply) : _reply(reply) {}
		virtual ~Reply() {}

		/**
		 * Is this reply valid & has no errors? NOTE : reply with NULL data will be treated as valid.
		 */
		operator bool() const;

		/**
		 * Get raw type. For DEBUG
		 */
		int Type() const;

		/** Detail reply data type. */
		bool IsString() const;
		bool IsArray() const;
		bool IsInt() const;
		bool IsNil() const;

		/** Get data as special type. */
		const char * AsError() const;
		std::string AsString() const;
		int64_t AsInt() const;

		/** Array operation. */
		size_t Size() const;
		Reply Element(size_t n) const;

	private:
		redisReply * _reply;
	};

	/**
	 * Reply handler definition.
	 */
	typedef std::function<void(Reply &)> ReplyHandler;

	/**
	 * Redis connection(Async way).
	 */
	class Client {
	public:
		Client();
		virtual ~Client();

		/**
		 * Connect to Redis server.
		 *
		 * \param	host	Host address of Redis server.
		 * \param	port	Open port to connect with this server.
		 * \return Connection result.
		 */
		bool Connect(const std::string & host, int port);

		/**
		 * Disconnect with Redis server.
		 */
		void Disconnect();

		/**
		 * Send command to Redis server.
		 *
		 * \param	callback	Handler for reply.
		 * \param	cmd			Command format. See hiredis doc.
		 * \param	...			Parameter to build this command.
		 * \return Whether this command is sent to redis server successfully or not.
		 */
		bool Command(const ReplyHandler & callback, const char * cmd, ...);

	private:
		redisAsyncContext * _ctx;
		int _status;
		uint64_t _cbid;
		std::map<uint64_t, ReplyHandler> _callbacks;
		std::string _host;
		int _port;
	};
}

#endif//!   __REDIS_H_INCLUDED__